package cn.bonoon.kernel.annotations;

import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

/**
 * <pre>
 * 对转换的实体进行指定
 * 
 * 如果需要转值的实体没有使用本注解，则默认是使用<code>
 * read = {@link ReadModel#OPTIMIZE}
 * write = {@link WriteModel#NONE} </code>模式
 * 
 * 如果使用，并且没有指定值，则默认使用情况为：<code>
 * read = {@link ReadModel#READABLE}
 * write = {@link WriteModel#WRITABLE} </code>模式，即支持读写格式
 * </pre>
 * <pre>
 * 对数据实体进行转值的时候，分两种情况：
 * 一种是写值（即把值写到数据库实体里），一种是读值（即把数据库[实体]值写到普通的对象里）
 * 
 * 下面是这种情况能使用到的一些转换的注解：
 * 1.向数据库实体写值的情况：
 *   向数据库写值必须通过数据库实体（目前是这样），把普通实体转换成数据库实体，再把数据库实体
 *   交给hibernate进行持久化处理，写数据库有三种情况：
 *   1）只添加，即在添加的时候有效，修改时无效
 *   2）只更新，即在添加的时候无效，修改时有效
 *   3）添加和更新都有效
 *       <table>
 *       <tr><td>a）{@link Cipher}</td><td>对字段进行加密处理(两者有效)</td></tr>
 *       <tr><td>b）{@link CodeBuilder}</td><td>自动生成编码(只添加)</td></tr>
 *       <tr><td>c）{@link MD5Builder}</td><td>自动生成唯一的md5码(可指定)</td></tr>
 *       <tr><td>d）{@link Tag}</td><td>提取标签(两者有效)</td></tr>
 *       <tr><td>e）{@link Unique}</td><td>唯一值限定(两者有效)</td></tr>
 *       <tr><td>f）{@link Keyword}</td><td>关键词过滤(两者有效)</td></tr>
 *       </table>
 *       
 * 2.向普通实体里读值的情况：
 *   有两种读值的模式：
 *   1）普通读取模式；普通读取是指通过数据库对象，把数据库对象的值相应的赋给普通实体的对象
 *       <table>
 *         <tr><td>a){@link ArraySeparator}</td><td>读取字段，并生成数组(可与{@link ObjectClass}组合生成对象数组)</td></tr>
 *         <tr><td>b){@link Cipher}</td><td>对字段进行解密处理</td></tr>
 *         <tr><td>c){@link Cutoff}</td><td>截断字符串</td></tr>
 *         <tr><td>d){@link FormatString}</td><td>格式化字符串</td></tr>
 *         <tr><td>e){@link OptionArray}</td><td>把下标转换成相应的显示名</td></tr>
 *         <tr><td>f){@link Secrecy}</td><td>加密后显示</td></tr>
 *         <tr><td>g){@link ValueReader}</td><td>使用指定的方法读值</td></tr>
 *         <tr><td>h){@link ObjectClass}</td><td>使用特定的对象</td></tr>
 *       </table>
 *         
 *   2）直接（优化）模式：直接通过查询语句返回的值（对象数组）进行转值，不需要通过数据库实体，
 *     这种做法的优点是，如果数据库表（数据库实体）字段比较多，关联的对象比较多的时候，读取时
 *     只根据需要的字段来生成查询语句，不会把多余的字段读取过程，应用最多的情况应该是列表的展
 *     示或其它以集合的方式取数据的格式，如下拉选择框的数据集合等
 *     这种模式可以使用的注解有：
 *       <table>
 *         <tr><td>a){@link Cipher}</td><td>对字段进行解密处理</td></tr>
 *         <tr><td>b){@link Cutoff}</td><td>截断字符串</td></tr>
 *         <tr><td>c){@link FormatString}</td><td>格式化字符串</td></tr>
 *         <tr><td>d){@link OptionArray}</td><td>把下标转换成相应的显示名</td></tr>
 *         <tr><td>e){@link Secrecy}</td><td>加密后显示</td></tr>
 *         <tr><td>f){@link ObjectClass}</td><td>使用特定的对象</td></tr>
 *       </table>
 * <hr/>
 * 对字段的指定，应该使用{@link TransformField}
 * </pre>
 * 
 * <pre style='color:red;'>
 * 经过测试证明，当被转值的数据库实体对象中包含关联关系，并且当关联关系为null时，如果读取的模式使用{@link ReadModel#OPTIMIZE}
 * 则无法读取数据，因为当组成查询语句时，会使用join连接来连接几个表，当某个表为空时，关联的数据将会为空，
 * 所以这时使用ID来查询是无法取到值的，所以要改为{@link ReadModel#READABLE}模式来转值
 * 
 * 注意如果不需要写值的时候，把{@link #write()}属性设置为{@link WriteModel#NONE}来限制生成写值的转换类
 * </pre>
 * @author jackson
 *
 *@see TransformField
 */
@Target(TYPE)
@Retention(RUNTIME)
public @interface Transform {
	
	ReadModel read() default ReadModel.READABLE;
	
	String initReader() default "initReader";
	
	WriteModel write() default WriteModel.WRITABLE;
	
	String initWriter() default "initWriter";
}
